home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 242_01 / a51.c < prev    next >
Text File  |  1989-01-11  |  18KB  |  700 lines

  1. /*
  2.     HEADER:        CUG242;
  3.     TITLE:        8051 Cross-Assembler (Portable);
  4.     FILENAME:    A51.C;
  5.     VERSION:    0.4;
  6.     DATE:        11/09/1988;
  7.     SEE-ALSO:    A51.H;
  8.     AUTHORS:    William C. Colley III;
  9. */
  10.  
  11. /*
  12.               8051 Cross-Assembler in Portable C
  13.  
  14.         Copyright (c) 1985,1987 William C. Colley, III
  15.  
  16. Revision History:
  17.  
  18. Ver    Date        Description
  19.  
  20. 0.0    JUL 1987    Adapted from version 0.0 of my portable 8048 cross-
  21.             assembler.  WCC3.
  22.  
  23. 0.1    OCT 1987    Changed the order of DW constants and made trailing
  24.             colons on labels get trashed.  WCC3.
  25.  
  26. 0.2    AUG 1988    Fixed bug that swapped the machine codes for CPL A and
  27.             CLR A.  WCC3.
  28.  
  29. 0.3    AUG 1988    Fixed a bug in the command line parser that puts it
  30.             into a VERY long loop if the user types a command line
  31.             like "A51 FILE.ASM -L".  WCC3 per Alex Cameron.
  32.  
  33. 0.4    NOV 1988    Fixed a bug that made DJNZ direct,relative generate
  34.             the wrong opcode.  WCC3.
  35.  
  36. This file contains the main program and line assembly routines for the
  37. assembler.  The main program parses the command line, feeds the source lines
  38. to the line assembly routine, and sends the results to the listing and object
  39. file output routines.  It also coordinates the activities of everything.  The
  40. line assembly routine uses the expression analyzer and the lexical analyzer to
  41. parse the source line convert it into the object bytes that it represents.
  42. */
  43.  
  44. /*  Get global goodies:  */
  45.  
  46. #include "a51.h"
  47.  
  48. /*  Define global mailboxes for all modules:                */
  49.  
  50. char errcode, line[MAXLINE + 1], title[MAXLINE];
  51. int pass = 0;
  52. int eject, filesp, forwd, listhex;
  53. unsigned address, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
  54. FILE *filestk[FILES], *source;
  55. TOKEN token;
  56.  
  57. /*  Mainline routine.  This routine parses the command line, sets up    */
  58. /*  the assembler at the beginning of each pass, feeds the source text    */
  59. /*  to the line assembler, feeds the result to the listing and hex file    */
  60. /*  drivers, and cleans everything up at the end of the run.        */
  61.  
  62. static int done, ifsp, off;
  63.  
  64. void main(argc,argv)
  65. int argc;
  66. char **argv;
  67. {
  68.     SCRATCH unsigned *o;
  69.     int newline();
  70.     void asm_line();
  71.     void lclose(), lopen(), lputs();
  72.     void hclose(), hopen(), hputc();
  73.     void error(), fatal_error(), warning();
  74.  
  75.     printf("8051 Cross-Assembler (Portable) Ver 0.4\n");
  76.     printf("Copyright (c) 1985,1987 William C. Colley, III\n\n");
  77.  
  78.     while (--argc > 0) {
  79.     if (**++argv == '-') {
  80.         switch (toupper(*++*argv)) {
  81.         case 'L':   if (!*++*argv) {
  82.                 if (!--argc) { warning(NOLST);  break; }
  83.                 else ++argv;
  84.                 }
  85.                 lopen(*argv);
  86.                 break;
  87.  
  88.         case 'O':   if (!*++*argv) {
  89.                 if (!--argc) { warning(NOHEX);  break; }
  90.                 else ++argv;
  91.                 }
  92.                 hopen(*argv);
  93.                 break;
  94.  
  95.         default:    warning(BADOPT);
  96.         }
  97.     }
  98.     else if (filestk[0]) warning(TWOASM);
  99.     else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
  100.     }
  101.     if (!filestk[0]) fatal_error(NOASM);
  102.  
  103.     while (++pass < 3) {
  104.     fseek(source = filestk[0],0L,0);  done = off = FALSE;
  105.     errors = filesp = ifsp = pagelen = pc = 0;  title[0] = '\0';
  106.     while (!done) {
  107.         errcode = ' ';
  108.         if (newline()) {
  109.         error('*');
  110.         strcpy(line,"\tEND\n");
  111.         done = eject = TRUE;  listhex = FALSE;
  112.         bytes = 0;
  113.         }
  114.         else asm_line();
  115.         pc = word(pc + bytes);
  116.         if (pass == 2) {
  117.         lputs();
  118.         for (o = obj; bytes--; hputc(*o++));
  119.         }
  120.     }
  121.     }
  122.  
  123.     fclose(filestk[0]);  lclose();  hclose();
  124.  
  125.     if (errors) printf("%d Error(s)\n",errors);
  126.     else printf("No Errors\n");
  127.  
  128.     exit(errors);
  129. }
  130.  
  131. /*  Line assembly routine.  This routine gets expressions and tokens    */
  132. /*  from the source file using the expression evaluator and lexical    */
  133. /*  analyzer, respectively.  It fills a buffer with the machine code    */
  134. /*  bytes and returns nothing.                        */
  135.  
  136. static char label[MAXLINE];
  137. static int ifstack[IFDEPTH] = { ON };
  138.  
  139. static OPCODE *opcod;
  140.  
  141. void asm_line()
  142. {
  143.     SCRATCH char *p;
  144.     SCRATCH int i;
  145.     int isalph(), popc();
  146.     OPCODE *find_code(), *find_operator();
  147.     void do_label(), flush(), normal_op(), pseudo_op();
  148.     void error(), pops(), pushc(), trash();
  149.  
  150.     address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
  151.     for (i = 0; i < BIGINST; obj[i++] = NOP);
  152.  
  153.     label[0] = '\0';
  154.     if ((i = popc()) != ' ' && i != '\n') {
  155.     if (isalph(i)) {
  156.         pushc(i);  pops(label);
  157.         for (p = label; *p; ++p);
  158.         if (*--p == ':') *p = '\0';
  159.         if (find_operator(label)) { label[0] = '\0';  error('L'); }
  160.     }
  161.     else {
  162.         error('L');
  163.         while ((i = popc()) != ' ' && i != '\n');
  164.     }
  165.     }
  166.  
  167.     trash(); opcod = NULL;
  168.     if ((i = popc()) != '\n') {
  169.     if (!isalph(i)) error('S');
  170.     else {
  171.         pushc(i);  pops(token.sval);
  172.         if (!(opcod = find_code(token.sval))) error('O');
  173.     }
  174.     if (!opcod) { listhex = TRUE;  bytes = BIGINST; }
  175.     }
  176.  
  177.     if (opcod && opcod -> attr & ISIF) { if (label[0]) error('L'); }
  178.     else if (off) { listhex = FALSE;  flush();  return; }
  179.  
  180.     if (!opcod) { do_label();  flush(); }
  181.     else {
  182.     listhex = TRUE;
  183.     if (opcod -> attr & PSEUDO) pseudo_op();
  184.     else normal_op();
  185.     while ((i = popc()) != '\n') if (i != ' ') error('T');
  186.     }
  187.     source = filestk[filesp];
  188.     return;
  189. }
  190.  
  191. static void flush()
  192. {
  193.     while (popc() != '\n');
  194. }
  195.  
  196. static void do_label()
  197. {
  198.     SCRATCH SYMBOL *l;
  199.     SYMBOL *find_symbol(), *new_symbol();
  200.     void error();
  201.  
  202.     if (label[0]) {
  203.     listhex = TRUE;
  204.     if (pass == 1) {
  205.         if (!((l = new_symbol(label)) -> attr)) {
  206.         l -> attr = FORWD + VAL;
  207.         l -> valu = pc;
  208.         }
  209.     }
  210.     else {
  211.         if (l = find_symbol(label)) {
  212.         l -> attr = VAL;
  213.         if (l -> valu != pc) error('M');
  214.         }
  215.         else error('P');
  216.     }
  217.     }
  218. }
  219.  
  220. static void normal_op()
  221. {
  222.     SCRATCH unsigned *o, rmax, rmin, u;
  223.     int grab_a(), grab_comma(), grab_reg();
  224.     unsigned bit_expr(), dir_expr(), expr(), imm_expr();
  225.     TOKEN *lex();
  226.     void do_label(), error(), pushc(), s_error(), unlex();
  227.  
  228.     do_label();  o = obj;  *o = opcod -> valu;
  229.     rmax = (rmin = opcod -> attr & RARG) + ((opcod -> attr & RARGS) >> 5);
  230.     switch (opcod -> attr & OTYPE) {
  231.     case MOV:    if (!grab_reg()) {
  232.                 u = token.valu;
  233.                 if (grab_comma()) { s_error();  return; }
  234.                 switch (u) {
  235.                 case A:        if ((lex() -> attr & TYPE)
  236.                         == IMM) {
  237.                         *o = 0x74;  *++o = imm_expr();
  238.                         break;
  239.                         }
  240.                         *o = 0xe4;  unlex();  goto dec;
  241.                             
  242.                 case C:        *o = 0xa2;  *++o = bit_expr();
  243.                         break;
  244.  
  245.                 case DPTR:  if ((lex() -> attr & TYPE)
  246.                         == IMM) {
  247.                         *o = 0x90;  goto ljmp;
  248.                         }
  249.                         s_error();  return;
  250.  
  251.                 default:    if (u >= AT_R0 && u <= R7) {
  252.                         if (!grab_a()) *o = 0xf4 + u;
  253.                         else if ((token.attr & TYPE)
  254.                             == IMM) {
  255.                             *o = 0x74 + u;
  256.                             *++o = imm_expr();
  257.                         }
  258.                         else {
  259.                             *o = 0xa4 + u;  unlex();
  260.                             *++o = dir_expr();
  261.                         }
  262.                         break;
  263.                         }
  264.                         s_error();  return;
  265.                 }
  266.             }
  267.             else if ((token.attr & TYPE) == BVAL) {
  268.                 unlex();  u = bit_expr();
  269. move_bit:            if ((token.attr & TYPE) != SEP || grab_reg() ||
  270.                 token.valu != C) {
  271.                 s_error();  return;
  272.                 }
  273.                 *o = 0x92;  *++o = low(u);
  274.             }
  275.             else{
  276.                 unlex();  u = dir_expr();
  277.                 if ((token.attr & TYPE) == DOT) {
  278.                 token.attr = VAL;  token.valu = u;  unlex();
  279.                 pushc('.');  u = bit_expr();  goto move_bit;
  280.                 }
  281.                 if ((token.attr & TYPE) != SEP) {
  282.                 s_error();  return;
  283.                 }
  284.                 if (!grab_a()) { *o = 0xf5, *++o = u; }
  285.                 else if ((token.attr & TYPE) == IMM) {
  286.                 *o = 0x75;  *++o = u;  *++o = imm_expr();
  287.                 }
  288.                 else if ((token.attr & TYPE) != REG) {
  289.                 unlex();  *o++ = 0x85;  *++o = u;
  290.                 o[-1] = dir_expr();
  291.                 }
  292.                 else if (token.valu >= AT_R0 &&
  293.                 token.valu <= R7) {
  294.                 *o = 0x84 + token.valu;  *++o = u;
  295.                 }
  296.                 else if (token.valu == C) {
  297.                 *o = 0x92;  *++o = u;
  298.                 }
  299.                 else { s_error();  return; }
  300.             }
  301.             break;
  302.  
  303.     case MOVX:    if (grab_reg()) { s_error();  return; }
  304.             switch (token.valu) {
  305.                 case A:        if (!grab_comma() &&
  306.                         !gr